package org.ma1.cripto.aes.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.StringTokenizer;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import org.ma1.cripto.aes.operacion.OperacionBuilder;

public class AlgoritmoVis extends JPanel implements IListener {

	public static final int NO_OPERACION = -1;

	private static final String NombreOperaciones[] = {
			OperacionBuilder.AddRoundKey, OperacionBuilder.ByteSub,
			OperacionBuilder.ShiftRow, OperacionBuilder.MixColumns,
			OperacionBuilder.AddRoundKey, OperacionBuilder.ByteSub,
			OperacionBuilder.ShiftRow, OperacionBuilder.AddRoundKey };

	private static Color ColorOperaciones[] = { Color.blue,
			Color.yellow.darker(), Color.yellow.darker(),
			Color.yellow.darker(), Color.yellow.darker(), Color.red, Color.red,
			Color.red };

	private int indice = 0;

	private int operacionActual = NO_OPERACION;

	private int siguienteOperacion = 0;

	private Font fuenteOperaciones = new Font("Arial", Font.PLAIN, 4);
	private Font fuenteInfo = new Font("Arial", Font.PLAIN, 4);
	
	public AlgoritmoVis() {
		super();
		SoporteDispararCambio.getInstanceSoporteParametros().addListener(this);
		SoporteDispararCambio.getInstanceSoporteOperaciones().addListener(this);
		handle(IListener.TIPO_CAMBIO_COLOR, null);
	}

	public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2.scale(((double) this.getWidth()) / 100.0,
				((double) this.getHeight()) / 100.0);
		
		// Entrada
		g.setColor(Color.black);
		g2.fillOval(47, 5, 5, 5);

		// Conductos
		g2.drawLine(50, 7, 85, 7);
		g2.drawLine(85, 7, 85, 93);
		g2.drawLine(85, 93, 50, 93);

		// Operaciones
		g2.setStroke(new BasicStroke(0.5f));
		g2.setFont(fuenteOperaciones);
		for (int j = 0; j < NombreOperaciones.length; j++) {
			g2.setColor(Color.white);
			g2.fillRect(10, 12 + j * 10, 80, 5);
			g2.setColor(ColorOperaciones[j]);
			g2.drawRect(10, 12 + j * 10, 80, 5);
			g2.drawString(NombreOperaciones[j], 20, 16 + j * 10);
		}

		// Pintar operacion actual
		if (operacionActual != NO_OPERACION) {
			g2.setColor(ColorOperaciones[operacionActual]);
			g2.fillRect(10, 12 + operacionActual * 10, 80, 5);
			g2.setColor(Color.white);
			g2.setFont(new Font("Arial", Font.ITALIC, 4));
			g2.drawString(""+indice,10, 16 + operacionActual * 10);
			g2.setFont(new Font("Arial", Font.BOLD, 4));
			g2.drawString(NombreOperaciones[operacionActual] + " - Ejecutado",16, 16 + operacionActual * 10);
		}

		// Pintar siguiente operacion
		g2.setFont(new Font("Arial", Font.ITALIC, 4));
		if (siguienteOperacion != NO_OPERACION) {
			g2.setColor(Color.yellow.brighter().brighter());
			g2.fillRect(10, 12 + siguienteOperacion * 10, 80, 5);
			g2.setColor(Color.DARK_GRAY);
			g2.drawString(NombreOperaciones[siguienteOperacion]
					+ " - Siguiente operacion", 20,
					16 + siguienteOperacion * 10);
		}

		// Final
		g.setColor(Color.black);
		g2.fillOval(47, 90, 5, 5);
	}

	public int getOperacionActual() {
		return operacionActual;
	}

	public int getSiguienteOperacion() {
		return siguienteOperacion;
	}
	
	public void handle(int tipo, String txt) {
		if (tipo == IListener.TIPO_CAMBIO_COLOR) {
			cambioColor();
		} else if (tipo == IListener.TIPO_OPERACION_EJECUTADA) {
			operacionActual = siguienteOperacion;
			siguienteOperacion = (indice%4==0 && indice>2 && indice<36)?1:siguienteOperacion+1;
			if (siguienteOperacion==8) {
				indice = 0;
				siguienteOperacion=NO_OPERACION;
			} else {
				indice++;
			}
			repaint();
		} else if (tipo == IListener.TIPO_ALGORITMO_TERMINADO) {
			operacionActual = 7;
			siguienteOperacion = NO_OPERACION;
			indice = 0;
			repaint();
		} else if (tipo == IListener.TIPO_ALGORITMO_REINICIAR) {
			operacionActual = NO_OPERACION;
			siguienteOperacion = 0;
			indice = 0;
			repaint();
		}
	}

	private void cambioColor() {
		Color b1 = (Color) Parametros.getCurrentInstance().getParametro(
				"algoritmo.color1");
		Color b2 = (Color) Parametros.getCurrentInstance().getParametro(
				"algoritmo.color2");
		Color b3 = (Color) Parametros.getCurrentInstance().getParametro(
				"algoritmo.color3");

		ColorOperaciones[0] = b1;
		for (int k = 1; k < 5; k++) {
			ColorOperaciones[k] = b2;
		}
		for (int k = 5; k < ColorOperaciones.length; k++) {
			ColorOperaciones[k] = b3;
		}
		repaint();
	}
}
